package net.opentsdb.plugin;

import com.stumbleupon.async.Deferred;
import net.opentsdb.core.TSDB;
import net.opentsdb.stats.StatsCollector;
import net.opentsdb.utils.Assert;
import net.opentsdb.utils.Config;
import net.opentsdb.plugin.enums.PluginStates;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 包装类
 *     包装相关插件，提供tsdb使用
 *
 */
public class TsdbPluginLoader {

    private PluginManager pluginManager;
    private TSDB tsdb;
    private Config config;
    private Map<Class,PluginOperator> map;

    public TsdbPluginLoader(TSDB tsdb){
        this.tsdb = tsdb;
        this.config = tsdb.getConfig();
        pluginManager = new DefaultPluginManager();
        map = new HashMap<>();

        // init plugins
        for(PluginStates state: PluginStates.values()){
            addPlugin(state.getName(), state.getPlugin(),state.getClazz());
        }
    }

    /**
     *
     *
     * @param enable
     * @param pluginName
     * @param clazz
     * @return
     */
    private boolean addPlugin(String enable, String pluginName, Class clazz){
        Assert.notNull(clazz,enable+" class con't be null");

        // 开关未开启
        if(!config.getBoolean(enable)) return false;

        List<PluginOperator> pluginList = pluginManager.getExtensions(clazz);
        //未找到实现的接口插件
        if(pluginList == null || pluginList.size() == 0) return false;

        // 返回第一个匹配的，否则就返回第一个
        for(PluginOperator operator: pluginList){
            if(operator.getClass().getName().equals(pluginName)){
                map.put(clazz, operator);
                return true;
            }
        }

        map.put(clazz, pluginList.get(0));
        return true;
    }

    /**
     * 初始化plugin
     */
    public void initializePlugin(){
        for(Map.Entry<Class, PluginOperator> entry:map.entrySet()){
            entry.getValue().initialize(tsdb);
        }
    }

    /**
     * collect stats
     * @param collector
     */
    public void collectStats(final StatsCollector collector){
        for(Map.Entry<Class, PluginOperator> entry:map.entrySet()){
            try {
                PluginStates pluginState = PluginStates.byClazz(entry.getKey());
                String plugin = pluginState==null?"":pluginState.getPlugin();
                collector.addExtraTag("plugin", plugin);
                entry.getValue().collectStats(collector);
            } finally {
                collector.clearExtraTag("plugin");
            }
        }
    }

    /**
     * 关闭plugin
     */
    public List<Deferred<Object>> shutdownPlugin(){
        List<Deferred<Object>> deferreds = new ArrayList<Deferred<Object>>();

        for(Map.Entry<Class, PluginOperator> entry:map.entrySet()){
            deferreds.add(entry.getValue().shutdown());
        }

        return deferreds;
    }

    /**
     * 判断插件是否存在
     *
     * @param clazz
     * @return
     */
    public boolean isEnable(Class clazz){
        return map.containsKey(clazz);
    }

    /**
     * 获取插件实例对象
     *
     * @param clazz
     * @return
     */
    public PluginOperator get(Class clazz){
        return map.get(clazz);
    }

}
